package com.songlanyun.modules.marketing.groupbuy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.songlanyun.common.enums.LockPrefixConstant;
import com.songlanyun.common.enums.MarketingConstant;
import com.songlanyun.common.enums.OrderConstant;
import com.songlanyun.common.enums.RightsOrderConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.DateUtils;
import com.songlanyun.common.utils.custom.DateCustomUtils;
import com.songlanyun.common.validator.ValidatorUtils;
import cn.hutool.core.map.MapUtil;
import com.songlanyun.modules.exception.OrderException;
import com.songlanyun.modules.gains.service.ShopOrderGainsService;
import com.songlanyun.modules.goods.model.vo.GoodsSlimVo;
import com.songlanyun.modules.marketing.groupbuy.entity.GroupBuyActivity;
import com.songlanyun.modules.marketing.groupbuy.entity.GroupBuyActivityGoods;
import com.songlanyun.modules.marketing.groupbuy.entity.GroupBuyTeamMember;
import com.songlanyun.modules.marketing.groupbuy.model.vo.TeamSlimVO;
import com.songlanyun.modules.marketing.groupbuy.service.GroupBuyActivityGoodsService;
import com.songlanyun.modules.marketing.groupbuy.service.GroupBuyActivityService;
import com.songlanyun.modules.marketing.groupbuy.service.GroupBuyTeamMemberService;
import com.songlanyun.modules.order.entity.ChildOrder;
import com.songlanyun.modules.order.entity.Order;
import com.songlanyun.modules.order.service.OrderService;
import com.songlanyun.modules.payorder.service.PayOrderService;
import com.songlanyun.modules.rabbitmq.DelayedConstant;
import com.songlanyun.modules.rabbitmq.service.SendMsgService;
import com.songlanyun.modules.rights.service.RightsOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.utils.PageUtils;
import com.songlanyun.common.utils.Query;

import com.songlanyun.modules.marketing.groupbuy.dao.GroupBuyTeamDao;
import com.songlanyun.modules.marketing.groupbuy.entity.GroupBuyTeam;
import com.songlanyun.modules.marketing.groupbuy.service.GroupBuyTeamService;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service("groupBuyTeamService")
public class GroupBuyTeamServiceImpl extends ServiceImpl<GroupBuyTeamDao, GroupBuyTeam> implements GroupBuyTeamService {

    @Autowired
    private GroupBuyTeamMemberService groupBuyTeamMemberService;

    @Autowired
    private GroupBuyActivityService groupBuyActivityService;

    @Autowired
    private GroupBuyActivityGoodsService groupBuyActivityGoodsService;

    @Autowired
    private RightsOrderService rightsOrderService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private PayOrderService payOrderService;

    @Autowired
    private ShopOrderGainsService shopOrderGainsService;


    @Override
    public GroupBuyTeam create(GroupBuyTeam entity) {
        ValidatorUtils.validateEntity(entity);
        this.baseMapper.insert(entity);
        return entity;
    }

    @Override
    public GroupBuyTeam modify(GroupBuyTeam entity) {
        ValidatorUtils.validateEntity(entity);
        this.baseMapper.updateById(entity);
        return entity;
    }

    @Override
    public void remove(Long id) {

    }

    /**
     * 分页查看拼团活动下面有那些团
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        Long groupBuyId = MapUtil.getLong(params, "group_buy_id");
        Long shopId = MapUtil.getLong(params, "shop_id");
        Integer status = MapUtil.getInt(params, "status");
        Integer personNumber = MapUtil.getInt(params, "person_number");
        String leaderMobile = MapUtil.getStr(params, "leader_mobile");
        String startTime = MapUtil.getStr(params, "start_time");
        String endTime = MapUtil.getStr(params, "end_time");
        Long startTimeTemp = 0L;
        Long endTimeTemp = 0L;
        if (StringUtils.isNotBlank(startTime)) {
            startTimeTemp = DateCustomUtils.dateStringToMilliSecond(startTime);

        }
        if (StringUtils.isNotBlank(endTime)) {
            endTimeTemp = DateCustomUtils.dateStringToMilliSecond(endTime);
        }

        LambdaQueryWrapper<GroupBuyTeam> query = new LambdaQueryWrapper<>();
        query.eq(shopId != null, GroupBuyTeam::getShopId, shopId);
        query.eq(groupBuyId != null, GroupBuyTeam::getGroupBuyId, groupBuyId);
        //0建团中（团长还没有支付），1建团成功，成团中（团长支付完成），2组团完成，3建团失败（团长未支付）4组团失败（时间到了人员不足）
        query.eq(status != null, GroupBuyTeam::getStatus, status);
        query.eq(personNumber != null, GroupBuyTeam::getGroupPersonNumber, personNumber);
        query.like(StringUtils.isNotBlank(leaderMobile), GroupBuyTeam::getLeaderUserMobile, leaderMobile);
        query.ge(startTimeTemp > 0, GroupBuyTeam::getStartTime, startTimeTemp);
        query.le(endTimeTemp > 0, GroupBuyTeam::getStartTime, endTimeTemp);

        IPage<GroupBuyTeam> page = this.page(
                new Query<GroupBuyTeam>().getPage(params),
                query
        );

        page.getRecords().forEach(o->{
            o.loadLeaderUserInfo();
        });

        return new PageUtils(page);
    }

    /**
     * 内部调用销售量增加
     * @param goodsId
     * @param activityId
     * @param saleNum
     * @return
     */
    private  GroupBuyActivityGoods incSaleNum(Long goodsId, Long activityId, Integer saleNum) {
        GroupBuyActivityGoods activityGoods = null;
        RLock lock = redissonClient.getLock(LockPrefixConstant.GROUP_BUY_GOODS + goodsId);
        lock.lock(2, TimeUnit.SECONDS);
        try {
            activityGoods = groupBuyActivityGoodsService.getByGoodsIdAndGroupBuyId(goodsId, activityId);
            activityGoods.incSaleNum(saleNum);
            groupBuyActivityGoodsService.updateById(activityGoods);
        }
        finally {
            lock.unlock();
        }
        return activityGoods;
    }

    /**
     * 下单开团(内部调用)
     *
     * @param order
     * @return
     */
    @Override
    public GroupBuyTeam createTeam(Order order) {

        this.validateGroupBuyActivityTime(order.getActivityId());
        GroupBuyActivity groupBuyActivity = groupBuyActivityService.getById(order.getActivityId());
        /**
         * 1、活动还没有开始
         */
        if (MarketingConstant.ActiveState.NOT_START.equals(groupBuyActivity.getActiveState())) {
            throw new RRException(OrderException.NO_START_NOT_ABLE_OPEN_TEAM);
        }

        /**
         * 2、活动已结束
         */
        if (MarketingConstant.ActiveState.FINISHED.equals(groupBuyActivity.getActiveState())) {
            throw new RRException(OrderException.ENDED_NOT_ABLE_OPEN_TEAM);
        }

        /**
         * 3、变更活动库存
         */
        ChildOrder childOrder = order.getChildOrderList(true).get(0);
        GroupBuyActivityGoods activityGoods = incSaleNum(childOrder.getGoodsId(), order.getActivityId(), childOrder.getNumber());

        /**
         * 4、开团
         */
        GroupBuyTeam groupBuyTeam = new GroupBuyTeam();
        groupBuyTeam.setShopId(order.getShopId());
        groupBuyTeam.setGroupBuyId(order.getActivityId());
        groupBuyTeam.setGroupBuyGoodsId(activityGoods.getId());
        groupBuyTeam.setLeaderUserId(order.getUserId());
        groupBuyTeam.setLeaderUserMobile(order.getMobile());
        groupBuyTeam.setGroupPersonNumber(activityGoods.getGroupPeopleNum());
        groupBuyTeam.setLimitTime(groupBuyActivity.getLimitHour());
        groupBuyTeam.setStartTime(0L);
        groupBuyTeam.setEndTime(0L);
        groupBuyTeam.setCompleteTime(null);
        groupBuyTeam.setStatus(OrderConstant.TeamStatus.CREATING);
        this.create(groupBuyTeam);
        /**
         * 5、添加团成员
         */
        groupBuyTeamMemberService.createMember(groupBuyTeam, order, true);
        return groupBuyTeam;
    }

    @Override
    public void validateGroupBuyActivityTime(Long activityId) {
        GroupBuyActivity groupBuyActivity = groupBuyActivityService.getById(activityId);
        /**
         * 1、活动还没有开始
         */
        if (MarketingConstant.ActiveState.NOT_START.equals(groupBuyActivity.getActiveState())) {
            throw new RRException(OrderException.NO_START_NOT_ABLE_OPEN_TEAM);
        }

        /**
         * 2、活动已结束
         */
        if (MarketingConstant.ActiveState.FINISHED.equals(groupBuyActivity.getActiveState())) {
            throw new RRException(OrderException.ENDED_NOT_ABLE_OPEN_TEAM);
        }

    }


    /**
     * 下单参团（内部调用）
     *
     * @param order
     * @return
     */
    @Override
    public GroupBuyTeam joinTeam(Order order) {
        GroupBuyTeam groupBuyTeam = this.loadById(order.getSponsorActivityId(), true);

        /**
         * 1、只有组团中的团队才可以加入
         */
        if (!OrderConstant.TeamStatus.CREAT_SUCCESS.equals(groupBuyTeam.getStatus())) {
            throw new RRException(OrderException.CREAT_SUCCESS_ABLE_JOIN);
        }

        //不要重复参团
        GroupBuyTeamMember member = groupBuyTeamMemberService.getMemberBy(groupBuyTeam.getId(), order.getUserId());
        if (member != null && member.getJoinStatus()) {
            throw new RRException(OrderException.REPEAT_JOIN_TEAM);
        }


        Integer count = groupBuyTeamMemberService.loadJoinSuccessCount(groupBuyTeam.getId());
        /**
         * 2、人员已满
         */
        if (count >= groupBuyTeam.getGroupPersonNumber()) {
            throw new RRException(OrderException.TEAM_MEMBER_ENOUGH);
        }

        /**
         * 3、组团时间过了,不能入团，但是入了团的人员支付时不受此限制
         */
        if (groupBuyTeam.getEndTime() > 0 && System.currentTimeMillis() >= groupBuyTeam.getEndTime()) {
            throw new RRException(OrderException.TEAM_EXPIRE);
        }


        /**
         * 5、变更活动库存
         */
        ChildOrder childOrder = order.getChildOrderList(true).get(0);
        incSaleNum(childOrder.getGoodsId(), order.getActivityId(), childOrder.getNumber());
        groupBuyTeamMemberService.createMember(groupBuyTeam, order, false);

        return groupBuyTeam;
    }

    /**
     * 订单支付成功（如果是建团中的，开团成功，如果是组团中的支付成功，同时如果人员正好满员,成员完成）
     *
     * @param order
     * @return
     */
    @Override
    public GroupBuyTeam paySuccess(Order order) {

        GroupBuyTeam groupBuyTeam = this.loadById(order.getSponsorActivityId(), true);
        GroupBuyTeamMember member = groupBuyTeamMemberService.getMemberBy(groupBuyTeam.getId(), order.getUserId());
        //更新团成员的支付状态和支付时间
        member.setPayStatus(OrderConstant.PaymentStatus.SUCCESS);
        member.setJoinStatus(true);
        member.setPayTime(DateCustomUtils.formatToDate(order.getPayTime()));
        groupBuyTeamMemberService.modify(member);
        /**
         * 如果是团长
         */
        if (member.getLeader()) {
            //建团成功
            groupBuyTeam.setStatus(OrderConstant.TeamStatus.CREAT_SUCCESS);
            groupBuyTeam.setStartTime(System.currentTimeMillis());
            groupBuyTeam.setEndTime(groupBuyTeam.computeEndTime());
            this.modify(groupBuyTeam);


        } else {
            //查询已成功支付的人员的数量
            Integer count = groupBuyTeamMemberService.loadValidMemberCount(groupBuyTeam.getId());
            //如果成员数满员
            if (count >= groupBuyTeam.getGroupPersonNumber()) {
                //更新团的状诚为组团成功
                groupBuyTeam.setStatus(OrderConstant.TeamStatus.TEAM_SUCCESS);
                groupBuyTeam.setCompleteTime(new Date());
                this.modify(groupBuyTeam);
                List<GroupBuyTeamMember> members = groupBuyTeamMemberService.loadValidMember(groupBuyTeam.getId());

                //同时把所有成员订单改成有效，这样就可以发货了
                members.forEach(o -> {
                    Order loadOrder = o.loadOrder();
                    loadOrder.setEffective(true);
                    orderService.modify(loadOrder);
                    //计算商家与会员分润所得
                    if ((!order.getExchange()) && order.getTotalAmount().compareTo(BigDecimal.ZERO) > 0) {
                        shopOrderGainsService.initCreate(order);
                    }


                    if(loadOrder.getThird()) {
                        try {
                            payOrderService.uploadOrderEvent(loadOrder);
                        }
                        catch (Exception ex)
                        {
                            log.info("拼团中的第三方商品订单报单失败，订单号："+loadOrder.getOrderCode());
                        }
                    }
                });

            }
        }
        return groupBuyTeam;
    }

    @Override
    public GroupBuyTeam loadById(Long teamId, Boolean tw) {
        GroupBuyTeam team = this.getById(teamId);
        if (team == null && tw) {
            throw new RRException(OrderException.TEAM_NOT_EXISTS);
        }
        return team;
    }

    /**
     * 过期没有组团成功的团
     *
     * @return
     */
    @Override
    public List<GroupBuyTeam> loadBuildExpire() {
        //这里做了5分钟的缓冲
        return this.list(new LambdaQueryWrapper<GroupBuyTeam>()
                .eq(GroupBuyTeam::getStatus, OrderConstant.TeamStatus.CREAT_SUCCESS)
                .gt(GroupBuyTeam::getEndTime, 0)
                .le(GroupBuyTeam::getEndTime, System.currentTimeMillis() - 5 * 60 * 1000));
    }

    /**
     * 人员不足组团失败
     *
     * @param team
     * @return
     */
    @Transactional
    @Override
    public GroupBuyTeam expireTeamHandle(GroupBuyTeam team) {


        //不是组团中的不能过期
        if(!OrderConstant.TeamStatus.CREAT_SUCCESS.equals(team.getStatus()))
        {
            throw new RRException("不是组团中的不能过期");
        }

        team.setStatus(OrderConstant.TeamStatus.TEAM_FAIL);
        this.modify(team);

        //变更活动库存
        List<GroupBuyTeamMember> groupBuyTeamMembers = groupBuyTeamMemberService.loadValidMember(team.getId());
        groupBuyTeamMembers.forEach(member -> {
            //回退拼团库存=========================================================
            Order order = member.loadOrder();
            ChildOrder childOrder = order.getChildOrderList(true).get(0);

            RLock lock = redissonClient.getLock(LockPrefixConstant.GROUP_BUY_GOODS + team.getGroupBuyGoodsId());
            lock.lock(2, TimeUnit.SECONDS);
            try{
                GroupBuyActivityGoods activityGoods = team.getGroupBuyActivityGoods();
                if(activityGoods!=null) {
                    groupBuyActivityGoodsService.release(activityGoods, childOrder.getNumber());
                    activityGoods.decSaleNum(childOrder.getNumber());
                    groupBuyActivityGoodsService.updateById(activityGoods);
                }
            }
            finally {
                lock.unlock();
            }

            //自动发起退款维权=====================================================
            rightsOrderService.systemAutoRefund(order, RightsOrderConstant.RightsOperatePerson.SYSTEM);

        });


        return team;
    }

    @Override
    public List<GroupBuyTeam> getListByAGIdAndShopId(Long shopId, Long activityGoodsId) {
        return this.list(new LambdaQueryWrapper<GroupBuyTeam>().eq(GroupBuyTeam::getShopId,shopId)
        .eq(GroupBuyTeam::getGroupBuyGoodsId,activityGoodsId)
        .eq(GroupBuyTeam::getStatus,OrderConstant.TeamStatus.CREAT_SUCCESS.getCode()));
    }

    @Override
    public PageUtils queryALLPage(Map<String, Object> params) {

        String startTime = MapUtil.getStr(params, "start_time");
        String endTime = MapUtil.getStr(params, "end_time");
        Long startTimeTemp = 0L;
        Long endTimeTemp = 0L;
        if (StringUtils.isNotBlank(startTime)) {
            startTimeTemp = DateCustomUtils.dateStringToMilliSecond(startTime);
            params.put("start_time_l",startTimeTemp);
        }

        if (StringUtils.isNotBlank(endTime)) {
            Date date = DateUtils.addDateDays( DateCustomUtils.stringToDate(endTime), 1);
            params.put("end_time_l",date.getTime());
        }

        IPage<TeamSlimVO> page =  this.baseMapper.queryAllPage(new Query<TeamSlimVO>().getPage(params), params);
        return new PageUtils(page);
    }


}
